#include "hal_tm1637.h"
#include "gd32e23x_gpio.h"
#include "systick.h"

//#define SDA_IN()            gpio_input_bit_get(TM_SCL_PORT, TM_SCL_PIN)
#define SDA_IN()            gpio_input_bit_get(TM_SCL_PORT, TM_SDA_PIN)
#define SDA_H()             gpio_bit_set(TM_SCL_PORT, TM_SDA_PIN)
#define SDA_L()             gpio_bit_reset(TM_SCL_PORT, TM_SDA_PIN)

#define SCL_H()             gpio_bit_set(TM_SDA_PORT, TM_SCL_PIN)
#define SCL_L()             gpio_bit_reset(TM_SDA_PORT, TM_SCL_PIN)

static uint8_t seg_table[] = {
	0x3F,/*0*/ 	0x06,/*1*/	0x5B,/*2*/	0x4F,/*3*/
    0x66,/*4*/	0x6D,/*5*/	0x7D,/*6*/	0x07,/*7*/
	0x7F,/*8*/	0x6F,/*9*/	0x77,/*10 A*/	0x7C,/*11 b*/
	0x58,/*12 c*/	0x5E,/*13 d*/	0x79,/*14 E*/	0x71,/*15 F*/
	0x76,/*16 H*/	0x38,/*17 L*/	0x54,/*18 n*/	0x73,/*19 P*/
	0x3E,/*20 U*/	0x00,/*21 黑屏*/
};

static void tm1637_start() {
    
    SCL_H(); //拉高时钟线
    SDA_H(); //拉高数据线

    delay_us(5); //延时
    SDA_L();            //产生下降沿
    delay_us(5); //延时
}

static void tm1637_stop() {
    SDA_L();            //拉低数据线
    SCL_H();            //拉高时钟线
    delay_us(5); //延时
    SDA_H();            //拉高数据线
    delay_us(5); //延时
}

static uint8_t tm1637_recv_ack() {
    uint8_t ack;
    SCL_L();            //拉低时钟线
    delay_us(5);
    SDA_H();            //端口读之前先置高
    SCL_H();            //拉高时钟线
    delay_us(5);

    ack = SDA_IN();        //读应答信号
    delay_us(5);     //延时
    SCL_L();                //拉低时钟线
    delay_us(5);
    return ack;
}

static void tm1637_send_byte(uint8_t dat) {

    for(int i = 0; i < 8;i++) {
        SCL_L();
        delay_us(5);
        if((dat & 0x01) == 0x01)
            SDA_H();
        else
            SDA_L();

        dat >>= 1;
        delay_us(5);
        SCL_H(); 
        delay_us(5);
    }
    SCL_L();
    delay_us(5);
    tm1637_recv_ack();
}

static void tm1637_write_cmd(uint8_t cmd) {
    tm1637_start();
    tm1637_send_byte(cmd);
    tm1637_stop();
}

static void tm1637_write_reg(uint8_t addr,uint8_t dat) {
    tm1637_start();
    tm1637_send_byte(addr);
    tm1637_send_byte(dat);
    tm1637_stop();
}

static int tm1637_show_num(uint8_t addr,uint8_t dat) {
    tm1637_write_reg(addr,seg_table[dat]);
    return 0;
}

static void tm1637_clear() {
    tm1637_write_cmd(DISMODE);
    tm1637_write_reg(TM_ADDR_0,0x00);
    tm1637_write_reg(TM_ADDR_1,0x00);
    tm1637_write_reg(TM_ADDR_2,0x00);
    tm1637_write_reg(TM_ADDR_3,0x00);
    tm1637_write_reg(TM_ADDR_4,0x00);
    tm1637_write_reg(TM_ADDR_5,0x00);
}

static uint8_t tm1637_read_key() {
    
    uint8_t rekey = 0;

    tm1637_start();
    tm1637_send_byte(READKEY);
    
    SDA_H();
    for(int i = 0; i < 8; i++) {
        SCL_L();
        delay_us(10);
        rekey = rekey >> 1;
        SCL_H();
        if (SDA_IN() == 1)
            rekey = rekey | 0x80;
        else
            rekey = rekey | 0x00;

        delay_us(10);
    }
    
    SCL_L();
    delay_us(2);

    while (SDA_IN() == 1) ;
    SCL_H();

    return rekey;
}

static void tm1637_gpio_init() {
    rcu_periph_clock_enable(TM_IO_RCU);
    
    gpio_mode_set(TM_SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, TM_SCL_PIN | TM_SDA_PIN);
    gpio_output_options_set(TM_SCL_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, TM_SCL_PIN | TM_SDA_PIN);

    tm1637_write_cmd(DISMODE);
    tm1637_clear();

    tm1637_write_cmd(DISCTRL);
}

static int tm1637_show_dec(uint16_t dec) {

    tm1637_write_cmd(DISMODE);
	for(int i = 3;i >= 0;i--) {
		if(dec == 0) {
			tm1637_write_reg(TM_ADDR_5 + i,seg_table[0]);
		} else {
			tm1637_write_reg(TM_ADDR_5 + i,seg_table[dec % 10]);
			dec /= 10;
		}
	}
    return 0;
}

static int tm1637_show_string(const char *data,int len) {
    
    return 0;
}

static int tm1637_show_hex(uint16_t dec) {

    tm1637_write_cmd(DISMODE);
	for(int i = 3;i >= 0;i--) {
		if(dec == 0) {
			tm1637_write_reg(TM_ADDR_5 + i,seg_table[0]);
		} else {
			tm1637_write_reg(TM_ADDR_5 + i,seg_table[dec % 16]);
			dec /= 16;
		}
	}

    return 0;
}


const tm1637_t g_tm1637_ = {
    tm1637_gpio_init,
    tm1637_read_key,
    tm1637_show_num, 
    tm1637_show_dec,
    tm1637_show_string,
    tm1637_show_hex
};